#include "stm32f1xx_hal.h"                  // Device header
#include "HardWare/LapCount.h"
#include "HardWare/retarget.h"
#include "HardWare/gpioEx.h"
int16_t LapCount;
TMR_STATUS TMR;
// 模块引脚定义
#define TMR1_INT_GPIO_PORT                GPIOB
#define TMR1_INT_GPIO_CLK_ENABLE()        do{__GPIOB_CLK_ENABLE();}while(0)
#define TMR1_INT_GPIO_PIN                 GPIO_PIN_0
#define TMR1_INT_EXTI_IRQ                 EXTI0_IRQn
#define TMR_IRQHandler                   EXTI0_IRQHandler

#define TMR2_INT_GPIO_PORT                GPIOB
#define TMR2_INT_GPIO_CLK_ENABLE()        do{__GPIOB_CLK_ENABLE();}while(0)
#define TMR2_INT_GPIO_PIN                 GPIO_PIN_1
#define TMR2_INT_EXTI_IRQ                 EXTI1_IRQn
#define TMR2_IRQHandler                   EXTI1_IRQHandler

#define TMR_STATUS_BUFF 2

void LapCount_Init(void)
{
    GPIO_InitTypeDef GPIO_InitStructure={0};
    TMR1_INT_GPIO_CLK_ENABLE();


    GPIO_InitStructure.Pin = TMR1_INT_GPIO_PIN;
    GPIO_InitStructure.Mode = GPIO_MODE_IT_RISING_FALLING;
    GPIO_InitStructure.Pull = GPIO_PULLUP;

    HAL_GPIO_Init(TMR1_INT_GPIO_PORT, &GPIO_InitStructure);

    HAL_NVIC_SetPriority(TMR1_INT_EXTI_IRQ, 0, 2);
    HAL_NVIC_EnableIRQ(TMR1_INT_EXTI_IRQ);


    GPIO_InitStructure.Pin = TMR2_INT_GPIO_PIN;
    GPIO_InitStructure.Mode = GPIO_MODE_IT_RISING_FALLING;
    GPIO_InitStructure.Pull = GPIO_PULLUP;

    HAL_GPIO_Init(TMR2_INT_GPIO_PORT, &GPIO_InitStructure);

    HAL_NVIC_SetPriority(TMR2_INT_EXTI_IRQ, 0, 2);
    HAL_NVIC_EnableIRQ(TMR2_INT_EXTI_IRQ);

#if 0
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
	
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB, &GPIO_InitStructure);
	
	GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource0);
	// GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource1);
	
	EXTI_InitTypeDef EXTI_InitStructure;
	// EXTI_InitStructure.EXTI_Line = EXTI_Line0 | EXTI_Line1;
    EXTI_InitStructure.EXTI_Line = EXTI_Line0;
	EXTI_InitStructure.EXTI_LineCmd = ENABLE;
	EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
	EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
	EXTI_Init(&EXTI_InitStructure);
	
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
	
	NVIC_InitTypeDef NVIC_InitStructure;
	NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
	NVIC_Init(&NVIC_InitStructure);
#endif
	// NVIC_InitStructure.NVIC_IRQChannel = EXTI1_IRQn;
	// NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	// NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
	// NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;
	// NVIC_Init(&NVIC_InitStructure);
    TMR_init();
}
int16_t LapCount_Get(void)
{
	int16_t Temp;
	Temp = LapCount;
	LapCount = 0;
	return Temp;
}

void EXTI0_IRQHandler(void)
{
    HAL_GPIO_EXTI_IRQHandler(TMR1_INT_GPIO_PIN);
    __HAL_GPIO_EXTI_CLEAR_IT(TMR1_INT_GPIO_PIN);   // 再次清除 防抖
}

void EXTI1_IRQHandler(void)
{
    HAL_GPIO_EXTI_IRQHandler(TMR2_INT_GPIO_PIN);
    __HAL_GPIO_EXTI_CLEAR_IT(TMR1_INT_GPIO_PIN);   // 再次清除 防抖
}

void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
    // TODO 中断后先判断TMR 状态，根据状态再进行计数处理 此期间GPIO 电平会多次读取，读取代码的耗时是否会影响电平准确性验证
    // TODO 信号存在抖动的情况下，先判断触发信号的有效性，再进行后续操作

    TMR_DrictionStatus s;
    GPIO_Trigger_Edge edge=NoneEdge;
    switch (GPIO_Pin) {
        case GPIO_PIN_0:
            s = TMR_Get_TMR1_Driction_Status(GPIOB,GPIO_PIN_0,GPIO_PIN_1);
            TMR_Get_Driction();

            break;
        case GPIO_PIN_1:
            s = TMR_Get_TMR2_Driction_Status(GPIOB,GPIO_PIN_0,GPIO_PIN_1);
            TMR_Get_Driction();

            break;
        default:
            break;

    }
    printf(" -->s %d\n",s);
}


LinkedListQueue* TMR_init()
{
    TMR.TMR_DrictionStatusQueue = newLinkedListQueue();
    TMR.TMR_Driction=ClockWise;
    TMR_push_back(TBD);
    TMR_push_back(TBD);
}
/**
 * @brief 边沿触发时，读取另一个TMR 电平状态, 得出当前霍尔状态
 * */
TMR_DrictionStatus TMR_Get_TMR1_Driction_Status(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin_TMR1,uint16_t GPIO_Pin_TMR2)
{
    TMR_DrictionStatus status=TBD;
    if((RisingEdge==GPIO_Pin_IT_Trigger_Event(GPIOx,GPIO_Pin_TMR1)) &&
    GPIO_PIN_SET==HAL_GPIO_ReadPin(GPIOx,GPIO_Pin_TMR2))
    {
        status=StatusA;
        TMR_push_back(StatusA);
    }
    else if((FallingEdge==GPIO_Pin_IT_Trigger_Event(GPIOx,GPIO_Pin_TMR1)) &&
            GPIO_PIN_SET==HAL_GPIO_ReadPin(GPIOx,GPIO_Pin_TMR2))
    {
        status=StatusB;
        TMR_push_back(StatusB);
    }
    return status;
}

TMR_DrictionStatus TMR_Get_TMR2_Driction_Status(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin_TMR1,uint16_t GPIO_Pin_TMR2)
{
    TMR_DrictionStatus status=TBD;
    if((RisingEdge==GPIO_Pin_IT_Trigger_Event(GPIOx,GPIO_Pin_TMR2)) &&
            GPIO_PIN_SET==HAL_GPIO_ReadPin(GPIOx,GPIO_Pin_TMR1))
    {
        status=StatusA;
        TMR_push_back(StatusA);
    }
    else if((RisingEdge==GPIO_Pin_IT_Trigger_Event(GPIOx,GPIO_Pin_TMR2)) &&
            GPIO_PIN_RESET==HAL_GPIO_ReadPin(GPIOx,GPIO_Pin_TMR1))
    {
        status=StatusB;
        TMR_push_back(StatusB);
    }

    return status;
}

TMR_Driction TMR_Get_Driction()
{
    // 获取队列中数据方向
    if(size(TMR.TMR_DrictionStatusQueue)<TMR_STATUS_BUFF){
        return TBD;
    }

    // A->B +1
    if((TMR.TMR_DrictionStatusQueue->front->data==StatusA) &&
        (TMR.TMR_DrictionStatusQueue->front->next->data==StatusB))
    {
        TMR.TMR_Driction = ClockWise;
        LapCount++;
    }
    else if((TMR.TMR_DrictionStatusQueue->front->data==StatusB) &&
            (TMR.TMR_DrictionStatusQueue->front->next->data==StatusA))
    {
        TMR.TMR_Driction = CounterClockWise;
        LapCount--;
    }
    return TMR.TMR_Driction;
}
void TMR_push_back(TMR_DrictionStatus TMR_DrictionStatus)
{
    push_back(TMR.TMR_DrictionStatusQueue,TMR_DrictionStatus);
    // 队列固定长度 TMR_STATUS_BUFF
    while (size(TMR.TMR_DrictionStatusQueue)>TMR_STATUS_BUFF){
        pop(TMR.TMR_DrictionStatusQueue);
    }
}
